应用、蓝图与视图函数
1.Flask的层级关系
- Flask 最上层是 app 的核心对象
- 在核心对象上可以新建若干蓝图,这个蓝图不能单独纯在,必须要和 app 关联。
- 在每个蓝图上还可以注册很多静态文件、视图函数、模板等
- 一个业务模块可以分为很多个蓝图 比如:
user
、book
。可以把视图函数注册到蓝图上,然后再关联 app ,来达到模块化文件的分隔。 - 之前的
book.py
放到了app/web/
路径下,就是考虑到了蓝图。app
属于是整个Flask应用层。web
属于是蓝图
2.代码规范化
应该讲一些初始化工作,放在对应层级的包的初始化文件 __init__.py
中。比如Flask核心应用app对象初始化应该放在应用层级app包的 __init__.py
中。
蓝图的初始化,应该放在对应蓝图层级web包的__init__.py
中,并且所有蓝图对应的试图函数都应该放在web目录下
1 | # app/__init__.py |
1 | # fisher.py |
3 用蓝图注册试图函数
1.在蓝图中注册视图函数
1 | # 实例化蓝图 |
2.蓝图是不能替代app应用的,在蓝图中注册了视图函数后,还需要将蓝图插入app
1 | #app/__init__.py |
3.单蓝图多模块拆分视图函数
蓝图,他的出发点,是为了分模块的。
什么是模块级别的呢?
比如一个web系统属于一个web模块;
一个提供给移动端使用的api是一个api模块;
一个内容管理系统是一个CMS。
我们不应该讲book,user这样的不同类别的py文件,做成多个蓝图(这样不是不行,只是小题大做了)
正确的方式是:
在一个模块的初识文件中定义蓝图对象,这个模块的不同文件都引入这个蓝图对象来注册路由函数。
并在模块的初始化文件中引入这些py文件来完成试图函数注册代码的执行
book.py
1 | #book.py |
后面还会有user模块。我们这里先建立一段伪代码
1 | #user.py |
web/init.py
1 | from flask import Blueprint |
4. Request对象
之前我们定义的
url
请求路径是rest
风格的/book/search/<q>/<page>
,Flask会将<>里的值自动映射成视图函数方法的参数。
但是如果需要将方法参数做为请求参数传入进来。
就需要用到Flask内置的
Request
了。
Request
里包含了HTTP
请求的详细信息,比如param
,method
,url
,remote
ip
等。
下面看一下我们之前search函数的改造来了解一下Requset获取请求参数的基本用法
1 | from flask import request |
Request
的args
属性是一个不可变字典(继承了python内置的dict)immutableDict
。里面放的就是http请求的参数。可以使用to_dict()
方法获取请求参数的原生可变字典request.args.to_dict()
注意,Flask的request是基于代理模式实现的。想让request正常使用,必须确保是http请求触发的函数或视图函数中使用
5. WTForms参数验证
WTForms
是一款优秀的参数验证框架。可以将参数验证抽离出一个模块。与业务代码解耦。
使用pipenv
引入WTForms
1 | pipenv install wtforms |
使用WTForms
需要自定义一个类继承wtforms
提供的Form
类,然后定义参数校验规则
1 | from wtforms import Form, StringField, IntegerField |
使用WTForms
book.py
1 | @web.route("/book/search/") |
6. 配置文件拆分
我们之前的YuShuBook
访问api
分页获取数据的时候,count
和start
是写死的。现在来完善这一部分操作。
首先看我们之前的代码,接受了count
,start
两个参数
1 | @classmethod |
考虑以下几点:
1.我们的试图函数接受的参数是
page
,考虑到代码的封装性,应该尽可能的隐藏细节,我们应该把计算
count
,start
的过程放到YuShuBook
的search_by_key
方法中来做
.
2.虽然计算
start
的方法很简单。但是这是一个单独的逻辑过程,不应该将这段过程放在访问api获取数据的方法中。
而应该封装成一个方法,以方法名来代替这段逻辑
.
3.count的值应该放到配置文件中,这样方便修改。
但是考虑到我们之前的配置
DEGUG
,IP
,PORT
等都属于私密配置,包括以后会使用的数据库信息等。而
COUNT
的值属于可公开的配置,所以应该把配置文件拆分成secure.py
和settings.py
。
secure.py
保存私有配置,在上传git的时候不应该上传此文件,settings.py
是共有配置
下面来看修改完后的代码yushu_book.py
1 | # flask提供了获取当前app的方法 |
app/web/settings.py
1 | PRE_PAGE = 15 |
app/web/secure.py
1 | DEBUG = True |
app/init.py
1 | def create_app(): |
7. 数据表创建方式
1.模块分成
首先先将项目的层级结构重新调整一下,
将helper
,httper
这些放在libs
目录下,作为常用库函数。
将yushu_book
放在spider
目录下,因为这里涉及到的访问外部api
,或者访问数据库,都更像一个小的爬虫
更新完了目录结构为
- web flask 的web视图函数蓝图
- libs 库函数
- form 参数验证
- spider 数据爬取
2.数据表创建方式
1.database first
是最普标的。直接在数据库中编写DML语句,建表。
2.model first
使用建模工具,根据绘制的数据模型,生成数据表。DMA最爱
3.code first
在代码中创建业务模型(实体类),自动反向生成数据表。
程序员最爱可以专注业务模型的设计,而不是数据库的设计
不需要关心数据库表以及数据库表是如何创建的,简化思维逻辑
数据库只是用来存储数据的,他的表之间的关系应该有业务来决定
3.ORM与Code first的区别
Code first
关注的是相关的数据表是怎么创建的,他解决的是创建数据的问题ORM(Object relation Map
不仅仅是解决数据创建的问题,还包含了数据的查询,更新,添加,删除。ORM希望我们通过操作一个个模型来间接操作数据库,所以说他的范围是更加广阔的。我们后面的所有的数据库操作都是通过ORM来操作的
定义第一个模型类以及反向生成
新建一个模块model,用于存储数据库表对应的业务模型,在编写model层的模型时,
一定要忘记数据库表,重点要放在业务模型的抽象中来
sqlalchemy
是一个类库,用于根据定义的model反向生成数据库表Flask_SqlAlchemy
是Flask
在sqlalchemy
基础上封装的一个组件。提供了更加人性化的API来操作数据库pipenv
按照pipenv install flask-sqlalchemy
1.编写模型类
1 | from sqlalchemy import Column,Integer,String |
2.将模型映射到数据库中
1.在模型类中引入Flask_SqlAlchemy,并做相关声明
app/models/book.py
1 | from sqlalchemy import Column, Integer, String |
2.在app中插入Flask_SqlAlchemy对象
app/init.py
1 | from app.models.book import db |
3.书写配置文件
app/secure.py
1 | # key-SQLALCHEMY_DATABASE_URI不能随意修改 |
cysql驱动需要安装
1 | pipenv install cymysql |
上面的操作完成以后启动项目,会报如下错误
1 | /Users/gaowenfeng/.local/share/virtualenvs/fisher-4xlkyzha/lib/python3.6/site-packages/flask_sqlalchemy/__init__.py:794: FSADeprecationWarning: SQLALCHEMY_TRACK_MODIFICATIONS adds significant overhead and will be disabled by default in the future. Set it to True or False to suppress this warning. |
这是因为在Flask
中,不是实例化了app
核心对象,其他的代码就可以直接用到。所以在上面第二部create_all()
方法中,应该将app
传入
修改后的代码
1 | def create_app(): |